package 实验五;

import week4.homework.RationalNumber;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.util.Stack;
import java.util.StringTokenizer;

/**
 * Created by besti on 2018/6/9.
 */
public class SocketServer3 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
        //1.建立一个服务器Socket(ServerSocket)绑定指定端口
        ServerSocket serverSocket=new ServerSocket(8181);
        //2.使用accept()方法阻止等待监听，获得新连接
        Socket socket=serverSocket.accept();
        //3.获得输入流
        InputStream inputStream=socket.getInputStream();
        BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
        //获得输出流
        OutputStream outputStream=socket.getOutputStream();
        PrintWriter printWriter=new PrintWriter(outputStream);
        //4.读取用户输入信息
        String info=null;
        String str ="";
        while(!((info = bufferedReader.readLine()) ==null)){
            System.out.println("用户传过来的后缀表达式的密文：" + info);
            str=info;
        }
        String []a=str.split(",");
        byte[] ab = new byte[a.length];
        for (int i=0;i<a.length;i++){
            ab[i]= Byte.parseByte(a[i]);
        }
        // 读取对方的DH公钥
        FileInputStream f1=new FileInputStream("Apub.dat");
        ObjectInputStream b1=new ObjectInputStream(f1);
        PublicKey pbk=(PublicKey)b1.readObject( );
        //读取自己的DH私钥
        FileInputStream f2=new FileInputStream("Bpri.dat");
        ObjectInputStream b2=new ObjectInputStream(f2);
        PrivateKey prk=(PrivateKey)b2.readObject( );
        // 执行密钥协定
        KeyAgreement ka=KeyAgreement.getInstance("DH");
        ka.init(prk);
        ka.doPhase(pbk,true);
        //生成共享信息
        byte[ ] sb=ka.generateSecret();
        for(int i=0;i<sb.length;i++){
            System.out.print(sb[i]+",");
        }
        System.out.println();
        SecretKeySpec k=new  SecretKeySpec(sb,0,24,"DESede");
        // 解密
        Cipher cp=Cipher.getInstance("DESede");
        cp.init(Cipher.DECRYPT_MODE, k);
        byte[] ptext = cp.doFinal(ab);
        // 显示明文
        String p=new String(ptext,"UTF8");
        System.out.println(p);
        //Java摘要算法- MD5
        String x = p;//用x代表解密后的密文，也就是我们需要计算的字符串。
        MessageDigest m= MessageDigest.getInstance("MD5");
        m.update(x.getBytes("UTF8"));
        byte s[ ]=m.digest( );
        String result="";
        for (int i=0; i<s.length; i++){
            result+=Integer.toHexString((0x000000ff & s[i]) |
                    0xffffff00).substring(6);
        }
        System.out.println(result);

        Comparision comparision = new Comparision();
        String reply = comparision.calculator(p);
        System.out.println("计算出的后缀表达式值是："+reply);
        //给客户一个响应
        printWriter.write(reply);
        printWriter.flush();
        //5.关闭资源
        printWriter.close();
        outputStream.close();
        bufferedReader.close();
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
    static class Comparision {
        Stack<String> stack = new Stack<String>();

        RationalNumber num1,num2,num3;

        public Comparision() {
            stack = new Stack<String>();
        }

        public String calculator(String q)
        {
            String op1, op2, result;
            String a;
            StringTokenizer tokenizer = new StringTokenizer(q);

            while (tokenizer.hasMoreTokens())
            {
                a = tokenizer.nextToken();

                if(a.equals("+") || a.equals("-") || a.equals("*") || a.equals("÷"))
                {
                    // 把栈顶的操作数弹出，转换为RationalNumber类型
                    op2 = stack.pop();
                    num2 = conToRantionalNum(op2);

                    // 继续把栈顶的操作数弹出，转换为RationalNumber类型
                    op1 = stack.pop();
                    num1 = conToRantionalNum(op1);

                    //计算结果
                    result = calculate(num1,a.charAt(0),num2);
                    stack.push(result.toString());
                }
                else
                    stack.push(a);
            }
            result = stack.pop();
            return result;
        }

        public RationalNumber conToRantionalNum (String a)
        {
            String numer,denom;  // numer分子，denom分母


            //  把分数a/b以"/"为标记分割开
            StringTokenizer tokenizer1 = new StringTokenizer(a,"/");
            numer = tokenizer1.nextToken();
            if (tokenizer1.hasMoreTokens())
            //  如果分母不为1
            {
                denom = tokenizer1.nextToken();
                num1 = new RationalNumber(Integer.parseInt(numer), Integer.parseInt(denom));
            }
            else
            //  如果分母为1
            {
                num1 = new RationalNumber(Integer.parseInt(numer), 1);
            }
            return num1;
        }

        // 计算+、-、*、÷
        public String calculate(RationalNumber op1, char operation, RationalNumber op2)
        {
            RationalNumber result = new RationalNumber(0,1);

            switch (operation)
            {
                case '+':
                    result = op1.add(op2);
                    break;
                case '-':
                    result = op1.subtract(op2);
                    break;
                case '*':
                    result = op1.multiply(op2);
                    break;
                case '÷':
                    result = op1.divide(op2);
                    break;
            }
            return result.toString();
        }
    }
}






